<template>
  <view class="recordStatus" :style="{ background: bgColor() }">
    <view
      v-if="recordStatus !== 3"
      class="recordStatus-title"
      :style="{ color: titleColor() }"
      >{{ title() }}</view
    >
    <view v-if="recordStatus !== 3" class="recordStatus-animation">
      <canvas type="2d" class="recwave-WaveView"></canvas>
    </view>
    <image
      v-if="recordStatus === 3"
      class="recordStatus-warn"
      src="@/pagesA/static/images/chat/record_warn.png"
    ></image>
    <view class="recordStatus-remind" :style="{ color: titleColor() }">{{
      remindStr()
    }}</view>
  </view>
</template>

<script setup lang="ts">
import { ref, getCurrentInstance, onMounted, onUnmounted } from "vue";
import { onShow } from "@dcloudio/uni-app";
import { audioDurationTimeStr } from "@/utils/util";
import kkToast from "@/utils/kkToast";

import Recorder from "recorder-core";
import "recorder-core/src/engine/mp3.js";
import "recorder-core/src/engine/mp3-engine.js";
//可选引入可视化插件
import "recorder-core/src/extensions/frequency.histogram.view.js";
import "recorder-core/src/extensions/lib.fft.js";
import RecordApp from "recorder-core/src/app-support/app.js";
//【所有平台必须引入】uni-app支持文件
import "@/uni_modules/Recorder-UniCore/app-uni-support.js";
// #ifdef MP-WEIXIN
//可选引入微信小程序支持文件
import "recorder-core/src/app-support/app-miniProgram-wx-support.js";
// #endif

var vue3This = getCurrentInstance().proxy; //必须定义到最外面，getCurrentInstance得到的就是当前实例this

const props = defineProps({
  recordStatus: {
    type: Number,
    default: 1, // 1 松开发送 2 松开手指，取消发送 3说话时间太短
  },
  time: {
    type: Number,
    default: 0,
  },
});

const isBeginRecord = ref(false);
const recordDuraiton = ref(0);
const title = () => {
  return audioDurationTimeStr(recordDuraiton.value);
};

const remindStr = () => {
  if (props.recordStatus === 1) {
    return "松开发送，上滑取消";
  } else if (props.recordStatus === 2) {
    return "松开手指，取消发送";
  } else if (props.recordStatus === 3) {
    return "说话时间太短";
  }
};

const bgColor = () => {
  if (props.recordStatus === 2) {
    return "#FA7A7B";
  } else {
    return "rgba(0, 0, 0, 0.6)";
  }
};
const titleColor = () => {
  if (props.recordStatus === 2) {
    return "#fff";
  } else {
    return "rgba(255, 255, 255, 0.8)";
  }
};

onMounted(() => {
  vue3This.isMounted = true;
  RecordApp.UniPageOnShow(vue3This); //onShow可能比mounted先执行，页面准备好了时再执行一次
  recReq();
});
onUnmounted(() => {
  recStop();
  RecordApp.Stop(); //清理资源，如果打开了录音没有关闭，这里将会进行关闭
});
onShow(() => {
  if (vue3This.isMounted) RecordApp.UniPageOnShow(vue3This); //onShow可能比mounted先执行，页面可能还未准备好
});

var recReq = () => {
  /****【在App内使用app-uni-support.js的授权许可】编译到App平台时仅供测试用（App平台包括：Android App、iOS App），不可用于正式发布或商用，正式发布或商用需先联系作者获得授权许可（编译到其他平台时无此授权限制，比如：H5、小程序，均为免费授权）
	获得授权许可后，请解开下面这行注释，并且将**部分改成你的uniapp项目的appid，即可解除所有限制；使用配套的原生录音插件或uts插件时可不进行此配置
	****/
  //RecordApp.UniAppUseLicense='我已获得UniAppID=*****的商用授权';

  if (RecordApp.UniIsApp()) {
    RecordApp.UniWebViewVueCall(
      vue3This,
      'this.testCall("这里测试一下直接调用renderjs中的方法")'
    );
  }
  console.log("正在请求录音权限...");
  isBeginRecord.value = false;
  setTimeout(() => {
    if (!isBeginRecord.value) {
      emit("audioIsNotPermission");
    }
  }, 1000);
  RecordApp.RequestPermission(
    () => {
      console.log("已获得录音权限，可以开始录音了", 2);
      isBeginRecord.value = true;
      recStart();
    },
    (msg, isUserNotAllow) => {
      if (isUserNotAllow) {
        uni.showModal({
          content: "获取授权失败,是否重新授权?",
          success: (res) => {
            if (res.confirm) {
              uni.openSetting({
                success: (res) => {},
              });
            } else if (res.cancel) {
              // 处理用户点击取消的逻辑
            }
          },
        });
        //这里你应当编写代码进行引导用户给录音权限，不同平台分别进行编写
        emit("audioIsNotPermission");
      }
      console.log(
        (isUserNotAllow ? "isUserNotAllow," : "") + "请求录音权限失败：" + msg,
        1
      );
    }
  );
};
var recStart = () => {
  console.log("正在打开...");
  RecordApp.Start(
    {
      type: "mp3",
      sampleRate: 16000,
      bitRate: 16,
      onProcess: (
        buffers,
        powerLevel,
        duration,
        sampleRate,
        newBufferIdx,
        asyncEnd
      ) => {
        //全平台通用：可实时上传（发送）数据，配合Recorder.SampleData方法，将buffers中的新数据连续的转换成pcm上传，或使用mock方法将新数据连续的转码成其他格式上传，可以参考Recorder文档里面的：Demo片段列表 -> 实时转码并上传-通用版；基于本功能可以做到：实时转发数据、实时保存数据、实时语音识别（ASR）等

        //注意：App里面是在renderjs中进行实际的音频格式编码操作，此处的buffers数据是renderjs实时转发过来的，修改此处的buffers数据不会改变renderjs中buffers，所以不会改变生成的音频文件，可在onProcess_renderjs中进行修改操作就没有此问题了；如需清理buffers内存，此处和onProcess_renderjs中均需要进行清理，H5、小程序中无此限制
        //注意：如果你要用只支持在浏览器中使用的Recorder扩展插件，App里面请在renderjs中引入此扩展插件，然后在onProcess_renderjs中调用这个插件；H5可直接在这里进行调用，小程序不支持这类插件；如果调用插件的逻辑比较复杂，建议封装成js文件，这样逻辑层、renderjs中直接import，不需要重复编写

        // recpowerx.value=powerLevel;
        // recpowert.value=formatTime(duration,1)+" / "+powerLevel;

        recordDuraiton.value = Math.floor(duration / 1000);
        if (duration >= 1000 * 60 * 10) {
          recStop();
        }

        //H5、小程序等可视化图形绘制，直接运行在逻辑层；App里面需要在onProcess_renderjs中进行这些操作
        // #ifdef H5 || MP-WEIXIN
        if (vue3This.waveView) {
          vue3This.waveView.input(
            buffers[buffers.length - 1],
            powerLevel,
            sampleRate
          );
        }
        // #endif
      },
      onProcess_renderjs: `function(buffers,powerLevel,duration,sampleRate,newBufferIdx,asyncEnd){
			//App中在这里修改buffers才会改变生成的音频文件
			//App中是在renderjs中进行的可视化图形绘制，因此需要写在这里，this是renderjs模块的this（也可以用This变量）；如果代码比较复杂，请直接在renderjs的methods里面放个方法xxxFunc，这里直接使用this.xxxFunc(args)进行调用
			if(this.waveView){
				this.waveView.input(buffers[buffers.length-1],powerLevel,sampleRate);
			}
		}`,

      takeoffEncodeChunk: !vue3This.takeoffEncodeChunkSet
        ? null
        : (chunkBytes) => {
            //全平台通用：实时接收到编码器编码出来的音频片段数据，chunkBytes是Uint8Array二进制数据，可以实时上传（发送）出去
            //App中如果未配置RecordApp.UniWithoutAppRenderjs时，建议提供此回调，因为录音结束后会将整个录音文件从renderjs传回逻辑层，由于uni-app的逻辑层和renderjs层数据交互性能实在太拉跨了，大点的文件传输会比较慢，提供此回调后可避免Stop时产生超大数据回传
          },
      takeoffEncodeChunk_renderjs: !vue3This.takeoffEncodeChunkSet
        ? null
        : `function(chunkBytes){
			//App中这里可以做一些仅在renderjs中才生效的事情，不提供也行，this是renderjs模块的this（也可以用This变量）
		}`,

      start_renderjs: `function(){
			//App中可以放一个函数，在Start成功时renderjs中会先调用这里的代码，this是renderjs模块的this（也可以用This变量）
			//放一些仅在renderjs中才生效的事情，比如初始化，不提供也行
		}`,
      stop_renderjs: `function(aBuf,duration,mime){
			//App中可以放一个函数，在Stop成功时renderjs中会先调用这里的代码，this是renderjs模块的this（也可以用This变量）
			this.audioData=aBuf; //留着给Stop时进行转码成wav播放
		}`,
    },
    () => {
      console.log("录制中 mp3", 2);
      RecordApp.UniFindCanvas(
        vue3This,
        [".recwave-WaveView"],
        `this.waveView=Recorder.FrequencyHistogramView({compatibleCanvas:canvas1, width:100, height:15
					,lineCount:20,position:0,minHeight:1,fallDuration:400,stripeEnable:false,mirrorEnable:true
					,linear:[0,"#ffffff",1,"#ffffff"]});
			`,
        (canvas1) => {
          vue3This.waveView = Recorder.FrequencyHistogramView({
            compatibleCanvas: canvas1,
            width: 100,
            height: 15,
            lineCount: 20,
            position: 0,
            minHeight: 1,
            fallDuration: 400,
            stripeEnable: false,
            mirrorEnable: true,
            linear: [0, "#ffffff", 1, "#ffffff"],
          });
        }
      );
    },
    (msg) => {
      console.log("开始录音失败：" + msg, 1);
    }
  );
};
const recStop = () => {
  console.log("正在结束录音...");
  RecordApp.Stop(
    (aBuf, duration, mime) => {
      //全平台通用：aBuf是ArrayBuffer音频文件二进制数据，可以保存成文件或者发送给服务器
      //App中如果在Start参数中提供了stop_renderjs，renderjs中的函数会比这个函数先执行

      // #ifdef APP || MP-WEIXIN
      //生成一个文件名
      var fileName = __LocalFileName("mp3");

      RecordApp.UniSaveLocalFile(
        fileName,
        aBuf,
        (savePath) => {
          if (duration <= 1000) {
            if (props.recordStatus === 1) {
              emit("audioIsToShort", savePath);
            }
            wx.getFileSystemManager().unlink({
              filePath: savePath,
              success: () => {},
              fail: () => {},
            });
          } else {
            if (props.recordStatus === 1) {
              emit("uploadAudio", savePath, Math.floor(duration / 1000));
            }
          }
        },
        (errMsg) => {
          console.error(errMsg);
        }
      );
      // #endif

      var recSet = (RecordApp.GetCurrentRecOrNull() || { set: { type: "mp3" } })
        .set;
      console.log(
        "已录制[" +
          mime +
          "]：" +
          formatTime(duration, 1) +
          " " +
          aBuf.byteLength +
          "字节 " +
          recSet.sampleRate +
          "hz " +
          recSet.bitRate +
          "kbps",
        2
      );
    },
    (msg) => {
      console.log("结束录音失败：" + msg, 1);
    }
  );
};

var formatTime = (ms, showSS) => {
  var ss = ms % 1000;
  ms = (ms - ss) / 1000;
  var s = ms % 60;
  ms = (ms - s) / 60;
  var m = ms % 60;
  ms = (ms - m) / 60;
  var h = ms,
    v = "";
  if (h > 0) v += (h < 10 ? "0" : "") + h + ":";
  v += (m < 10 ? "0" : "") + m + ":";
  v += (s < 10 ? "0" : "") + s;
  if (showSS) v += "″" + ("00" + ss).substr(-3);
  return v;
};
const __LocalFileName = (type) => {
  var now = new Date();
  var fileName =
    "local-" +
    now.getFullYear() +
    ("0" + (now.getMonth() + 1)).substr(-2) +
    ("0" + now.getDate()).substr(-2) +
    ("0" + now.getHours()).substr(-2) +
    ("0" + now.getMinutes()).substr(-2) +
    ("0" + now.getSeconds()).substr(-2) +
    ("00" + now.getMilliseconds()).substr(-3) +
    (Math.random() + "").substr(2, 6) +
    "." +
    (type || "bin");
  return fileName;
};

// 获取录制的音频时长
const getAudioDuration = () => {
  return recordDuraiton;
};

const emit = defineEmits(["clickAudio", "uploadAudio", "audioIsNotPermission"]);

defineExpose({ recReq, recStop, getAudioDuration });
</script>

<style lang="scss" scoped>
.recordStatus {
  position: fixed;
  left: 0;
  right: 0;
  top: calc(50% - 140rpx);
  margin: 0 auto;
  width: 280rpx;
  height: 280rpx;
  background: rgba(0, 0, 0, 0.6);
  border-radius: 24rpx;
  z-index: 99;
  display: flex;
  flex-direction: column;
  align-items: center;
  &-title {
    padding-top: 24rpx;
    font-size: 24rpx;
    color: rgba(255, 255, 255, 0.8);
    line-height: 28rpx;
  }
  &-animation {
    margin-top: auto;
    margin-bottom: auto;
    width: 106px;
    height: 15px;
  }

  &-animation canvas {
    width: 106px;
    height: 15px;
  }

  &-warn {
    margin-top: 82rpx;
    margin-bottom: auto;
    width: 16rpx;
    height: 116rpx;
  }
  &-remind {
    padding-bottom: 24rpx;
    font-size: 24rpx;
    color: rgba(255, 255, 255, 0.8);
    line-height: 28rpx;
  }
}
</style>

<style>
.recordStatus-animation canvas {
  width: 106px;
  height: 15px;
}
</style>
